Skip to content

Spec: limb decomposition discussion#669

Open
erik-3milabs wants to merge 8 commits into
spec/mainfrom
spec/limb_decomposition
Open

Spec: limb decomposition discussion#669
erik-3milabs wants to merge 8 commits into
spec/mainfrom
spec/limb_decomposition

Conversation

@erik-3milabs

Copy link
Copy Markdown
Collaborator

This PR introduces a section that discusses (and proves) some properties of performing operations on limb decompositions.

@erik-3milabs erik-3milabs requested a review from RobinJadoul June 15, 2026 13:09
@erik-3milabs erik-3milabs self-assigned this Jun 15, 2026
@erik-3milabs erik-3milabs added the spec Updates and improvements to the spec document label Jun 15, 2026
@github-actions

Copy link
Copy Markdown

Codex Code Review

Findings

  • Medium - Potential bug: spec/limbs_and_carries.typ:70 states the decomposition is (w_0, ..., w_(2n-2), 0, 0, ...) iff c_(2n-1) = 0, but the proof sums through w_(2n-1) and line 183 later concludes (w_0, ..., w_(2n-1), 0, ...). The lemma as written is false for products that need the top limb, e.g. L=10, n=2, x=y=99 needs w_3=9 while c_3=0. Fix the lemma to include w_(2n-1) or strengthen the condition if the high limb must be zero.

  • Medium - Potential bug: spec/limbs_and_carries.typ:188 has - mu (2n-i) in the combined carry bound, contradicting the part 2 bound at lines 140 and 175, which use + mu (...). As written, the “upper bound” becomes negative near i = 2n-1 even though carries are nonnegative. This should likely be + mu (2n-i).

  • Low - Potential bug: spec/limbs_and_carries.typ:48 drops the outer multiplication sum and leaves i free; line 50 similarly leaves r free in the second term. The intended formula is recovered later, but the derivation is invalid as written.

No Rust/VM/security-relevant implementation changes are in this diff. I did not run a Typst build because typst/shiroa are not installed in this environment.

Comment thread spec/limbs_and_carries.typ Outdated
Comment thread spec/limbs_and_carries.typ Outdated
Comment thread spec/limbs_and_carries.typ Outdated
Comment thread spec/limbs_and_carries.typ Outdated
Comment thread spec/limbs_and_carries.typ Outdated
Comment thread spec/limbs_and_carries.typ Outdated
Comment thread spec/limbs_and_carries.typ Outdated
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Erik <159244975+erik-3milabs@users.noreply.github.com>
@erik-3milabs

Copy link
Copy Markdown
Collaborator Author

The three points from Codex's review have been addressed in the previous commit (7111791)

@erik-3milabs erik-3milabs mentioned this pull request Jun 16, 2026
Comment thread spec/limbs_and_carries.typ Outdated
Comment thread spec/limbs_and_carries.typ
Comment thread spec/limbs_and_carries.typ Outdated
:=(overline(w)_i + c_(i-1) - w_i ) dot L^(-1)
= floor.l (overline(w)_i + c_(i-1)) dot L^(-1) floor.r.$
Hence, $c_i$ is maximized when both $overline(w)_i$ and $c_(i-1)$ are, and thus,
by induction, when $overline(w)_j$ is maximized for all $j in [0, i]$.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically the [0, i] should be [0, i), I suppose. Maybe just "for all i < j"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope: [0, i]: c_i is defined in terms of overline(w)_i and thus, it is maximized when all overline(w)_j are for j <= i.

Also, i<j would be swapping the terms.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inclusion: yeah, fair
The second part was me swapping the operands accidentally, but I suppose the question then becomes whether j ≤ i is nicer to read that j ∈ [0, i]

Comment thread spec/limbs_and_carries.typ Outdated
Comment thread spec/limbs_and_carries.typ Outdated
This includes $k = n-1$, which yields $c_(n+(n-1)) = c_(2n-1) <= mu - delta'$.
Moreover, $c_(2n) <= floor.l (mu - delta') dot L^(-1) floor.r = 0$ since $mu in [L]$ and thus $c_(2n + i) = 0$ for all $i >= 0$.
Applying this to @lm:wi_decomp_f, we conclude that $(w_0, w_1, ..., w_(2n-1), 0, 0, ...) in [L]^*$ is the unique limb decomposition
of $f_(alpha, mu) (x, y, z)$ when $mu = 0$ and $alpha < L$, or $mu = 1$ and $alpha <= 2$.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There bounds don't match the μ, α ∈ [L/2 - 1] from @lm:wi_decomp_f

Comment thread spec/limbs_and_carries.typ Outdated

Now, observe that
$
&max_(i in [2n]) min(mu (i+1) (L-1) + alpha - mu - delta, mu (2n-i-1)(L-2) + mu (2n-i) - delta')\

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully understand where this comes from, in particular the min.
I can see the 2n coming from n - (i - n), but somehow this assumes that the correct bound for one half is the minimum out of the two possible values, which is not a priori obvious.

e.g. for i = n - 1, we get min(μ n (L - 1) + α - μ - δ, μ n (L - 1) + μ - δ'), which would depend on the relation between μ and α, and for e.g. the case α = L/2 - 2, μ = 1 this would (wrongly) choose the second as upper bound.
Or in the degenerate case where μ = 0, we'd get min(α - 1, 0) = 0 everywhere as upper bound.

Probably the correct rephrasing is to take max(max_{i ∈ [n}(...), max_{k ∈ n}(...)) instead

@erik-3milabs erik-3milabs requested a review from RobinJadoul June 22, 2026 13:55
Comment thread spec/add.typ
Comment on lines +31 to +35
Note that the correctness of these constraints follows from @lm:limb-decomposition-constraint-correctness, when applied to $(S, L, C, alpha, mu) = (2^64, 2^32, 2, 2, 0)$:
- the definition of `carry` matches that of @eq:def_ci and @eq:c_-1_is_zero,
- @eq:range_ci is enforced by @add:c:carry, and
- @eq:range_wi follows from @add:a:sum.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm noticing that the labels of these references are broken; local referencing inside the limb-decomposition section is fine. Are you OK with using the equate package despite these broken labels?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly are we getting from equate? And does not using it fix the labels?

@RobinJadoul RobinJadoul left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple nits, some typography, and some weirdness left surrounding the corollary. But I think next pass should be there

Comment thread spec/add.typ
Comment on lines +31 to +35
Note that the correctness of these constraints follows from @lm:limb-decomposition-constraint-correctness, when applied to $(S, L, C, alpha, mu) = (2^64, 2^32, 2, 2, 0)$:
- the definition of `carry` matches that of @eq:def_ci and @eq:c_-1_is_zero,
- @eq:range_ci is enforced by @add:c:carry, and
- @eq:range_wi follows from @add:a:sum.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly are we getting from equate? And does not using it fix the labels?

Let $[X]$ denote the set ${0, ..., X-1} subset.eq NN$.
Let $S := L^n in NN$ be an upper bound on the integers we want to represent,
where $L in NN without {0, 1}$ is the number of values a limb can represent
and $n in N$ denotes the number of limbs.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
and $n in N$ denotes the number of limbs.
and $n in NN$ denotes the number of limbs.

where $L in NN without {0, 1}$ is the number of values a limb can represent
and $n in N$ denotes the number of limbs.

Observe that for all $x in [S]$, there exists a unique tuple of integers

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Observe that for all $x in [S]$, there exists a unique tuple of integers
Observe that for all $x in [S]$, there exists a unique "limb decomposition"

= sum_(i=0)^(n-1) x_i dot L^i.
$ #<eq:decomposition>
To simplify future notation, we define $x_i := 0$ for all $i >= n$.
Next, we define the family of multi-linear functions

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

paragraph break?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we care that the functions are multi-linear?

To simplify future notation, we define $x_i := 0$ for all $i >= n$.
Next, we define the family of multi-linear functions
$
f_(mu, alpha) (x, y, z) := sum_(m in [mu]) (x^((m)) dot y^((m))) + sum_(a in [alpha]) z^((a))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make the variables boldface, as they're vectorial

c_i <= &max(&max_(i in [n]) #h(1em) mu (i+1) (L-1) + alpha - mu - delta,\
&max_(k in [n]) #h(1em) mu (2n-k-1)(L-2) + mu (2n-k) - delta')\
&= max(& mu n (L-1) + alpha - mu - delta, mu (2n-1)(L-2) + 2 mu n - delta')\
&= mu n (L-1) + alpha - mu - delta

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless the 2s disappear, this doesn't hold, afaict; when they do disappear, it works (with L ≥ 2), except maybe some weirdness with the deltas I didn't work through entirely

$
]

Note that this upper bound is tight:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this tight, if we're using the upper bound from the first half of the coefficients? Does this refer to the lemma 3 bound instead of the corollary?

Note that this upper bound is tight:
$c_(n+k)$ achieves the bound for all $k in [n]$ when $x^((m)) = y^((m)) = z^((a)) = S-1$ for all $m in [mu]$ and $a in [alpha]$.
For $k = n-1$, this yields $c_(n+(n-1)) = c_(2n-1) <= mu - delta'$, which evaluates to zero when $mu = 0$ and $alpha < L$, or $mu = 1$ and $alpha <= 2$.
We can therefore conclude that $(w_0, w_1, ..., w_(2n-1)) in [L]^(2n)$ is a valid $2n$-limb decomposition of $f_(mu, alpha) (x, y, z)$ in these cases.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We can therefore conclude that $(w_0, w_1, ..., w_(2n-1)) in [L]^(2n)$ is a valid $2n$-limb decomposition of $f_(mu, alpha) (x, y, z)$ in these cases.
We can therefore conclude that $(w_0, w_1, ..., w_(2n-1)) in [L]^(2n)$ is a valid $2n$-limb decomposition of $f_(mu, alpha) (bold(x), bold(y), bold(z))$ in these cases.

where the utilized upper bound
$overline(w)_i <= mu n(L-1)^2 + alpha (L-1)$
can be extracted from the proofs of @lm:carry-upperbound-pt1 and @lm:carry-upperbound-pt2.
Moreover, observe that $|X_i inter [L]| <= 1$ since $C < frac(p,L, style:"horizontal")$.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe more clear as

Suggested change
Moreover, observe that $|X_i inter [L]| <= 1$ since $C < frac(p,L, style:"horizontal")$.
Moreover, observe that $|X_i inter [L]| <= 1$ since $0 <= C L < p$.

$
where the utilized upper bound
$overline(w)_i <= mu n(L-1)^2 + alpha (L-1)$
can be extracted from the proofs of @lm:carry-upperbound-pt1 and @lm:carry-upperbound-pt2.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably we want to ref the corollary here, otherwise it's not doing much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

spec Updates and improvements to the spec document

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants